package com.mrzhou.log.aspect;

import com.mrzhou.core.tool.utils.ClassUtil;
import com.mrzhou.log.annotation.ApiLog;
import com.mrzhou.log.annotation.ApiLogIgnore;
import com.mrzhou.log.event.ApiLogEvent;
import com.mrzhou.log.publisher.ApiLogPublisher;
import com.mrzhou.web.util.WebArgumentUtil;
import com.mrzhou.web.util.WebUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;

import java.lang.reflect.Method;
import java.time.LocalDate;
import java.util.Date;
import java.util.Map;

/**
 * @author qiang.zhou
 */
@Aspect
@Slf4j
public class CallLogAspect {

    /**
     * 透过切面的方式获取请求的参数信息
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("execution(* com.mrzhou.*.controller..*.*(..)) || " +
            "@within(org.springframework.web.bind.annotation.RestController) || " +
            "execution(* org.springframework.security.oauth2.provider.endpoint.*.postAccessToken(..))")
    public Object aroundLog(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info(String.format("====== %s: 记录请求日志", WebUtil.getUri()));
        // 请求时间
        Date requestTime = new Date();
        // 获取代理对象的类名称
        String className = joinPoint.getTarget().getClass().getName();
        // 获取代理的方法名称
        String methodName = joinPoint.getSignature().getName();
        MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature();
        Method targetMethod = methodSignature.getMethod();
        if(checkSaveLogReg(targetMethod)) {
            return joinPoint.proceed();
        }
        // 获取请求方法上的参数
        Map<String, Object> params = WebArgumentUtil.handlerArgumentToMap(targetMethod, joinPoint);

        long startTime = System.currentTimeMillis();
        Object result = joinPoint.proceed();

        long runTime = System.currentTimeMillis() - startTime;
        // 推送
        ApiLogPublisher.publisherEvent(className, methodName, runTime, requestTime, params, result);
        return result;
    }

    /**
     * 日志保存规则
     * @return true 忽略本次请求的日志
     */
    private boolean checkSaveLogReg(Method targetMethod) {
        ApiLog apiLog = ClassUtil.getAnnotation(targetMethod, ApiLog.class);
        ApiLogIgnore apiLogIgnore = ClassUtil.getAnnotation(targetMethod, ApiLogIgnore.class);
        if (null != apiLog) {
            return true;
        }

        if(null != apiLog && apiLog.ignore()) {
            return true;
        }

        if (null != apiLogIgnore) {
            return true;
        }
        return false;
    }

}
